home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / EnhancedMesh / EnhancedMesh.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  33.2 KB  |  742 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: EnhancedMesh.cpp
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "resource.h"
  10.  
  11. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  12. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  13.  
  14. #define MESHFILENAME L"dwarf\\dwarf.x"
  15.  
  16.  
  17. //--------------------------------------------------------------------------------------
  18. // Global variables
  19. //--------------------------------------------------------------------------------------
  20. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  21. ID3DXSprite*            g_pTextSprite = NULL;   // Sprite for batching draw text calls
  22. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  23. CModelViewerCamera      g_Camera;               // A model viewing camera
  24. IDirect3DTexture9*      g_pDefaultTex = NULL;   // Default texture for texture-less material
  25. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  26. CDXUTDialog             g_HUD;                  // dialog for standard controls
  27. CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
  28. ID3DXMesh*              g_pMeshSysMem = NULL;   // system memory version of mesh, lives through resize's
  29. ID3DXMesh*              g_pMeshEnhanced = NULL; // vid mem version of mesh that is enhanced
  30. UINT                    g_dwNumSegs = 2;        // number of segments per edge (tesselation level)
  31. D3DXMATERIAL*           g_pMaterials = NULL;    // pointer to material info in m_pbufMaterials
  32. LPDIRECT3DTEXTURE9*     g_ppTextures = NULL;    // array of textures, entries are NULL if no texture specified
  33. DWORD                   g_dwNumMaterials = NULL;// number of materials
  34. D3DXVECTOR3             g_vObjectCenter;        // Center of bounding sphere of object
  35. FLOAT                   g_fObjectRadius;        // Radius of bounding sphere of object
  36. D3DXMATRIXA16           g_mCenterWorld;         // World matrix to center the mesh
  37. ID3DXBuffer*            g_pbufMaterials = NULL; // contains both the materials data and the filename strings
  38. ID3DXBuffer*            g_pbufAdjacency = NULL; // Contains the adjacency info loaded with the mesh
  39. bool                    g_bUseHWNPatches = true;
  40. bool                    g_bWireframe = false;
  41.  
  42.  
  43. //--------------------------------------------------------------------------------------
  44. // UI control IDs
  45. //--------------------------------------------------------------------------------------
  46. #define IDC_TOGGLEFULLSCREEN    1
  47. #define IDC_TOGGLEREF           3
  48. #define IDC_CHANGEDEVICE        4
  49. #define IDC_FILLMODE            5
  50. #define IDC_SEGMENTLABEL        6
  51. #define IDC_SEGMENT             7
  52. #define IDC_HWNPATCHES          8
  53.  
  54.  
  55. //--------------------------------------------------------------------------------------
  56. // Forward declarations 
  57. //--------------------------------------------------------------------------------------
  58. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  59. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  60. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  61. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  62. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  63. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  64. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  65. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  66. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  67. void    CALLBACK OnLostDevice();
  68. void    CALLBACK OnDestroyDevice();
  69.  
  70. void    InitApp();
  71. HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh );
  72. void    RenderText();
  73. HRESULT GenerateEnhancedMesh( IDirect3DDevice9 *pd3dDevice, UINT cNewNumSegs );
  74.  
  75.  
  76. //--------------------------------------------------------------------------------------
  77. // Entry point to the program. Initializes everything and goes into a message processing 
  78. // loop. Idle time is used to render the scene.
  79. //--------------------------------------------------------------------------------------
  80. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  81. {
  82.     // Set the callback functions. These functions allow the sample framework to notify
  83.     // the application about device changes, user input, and windows messages.  The 
  84.     // callbacks are optional so you need only set callbacks for events you're interested 
  85.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  86.     // framework won't be able to reset your device since the application must first 
  87.     // release all device resources before resetting.  Likewise, if you don't handle the 
  88.     // device created/destroyed callbacks then the sample framework won't be able to 
  89.     // recreate your device resources.
  90.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  91.     DXUTSetCallbackDeviceReset( OnResetDevice );
  92.     DXUTSetCallbackDeviceLost( OnLostDevice );
  93.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  94.     DXUTSetCallbackMsgProc( MsgProc );
  95.     DXUTSetCallbackKeyboard( KeyboardProc );
  96.     DXUTSetCallbackFrameRender( OnFrameRender );
  97.     DXUTSetCallbackFrameMove( OnFrameMove );
  98.  
  99.     // Show the cursor and clip it when in full screen
  100.     DXUTSetCursorSettings( true, true );
  101.  
  102.     InitApp();
  103.  
  104.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  105.     // device for the application. Calling each of these functions is optional, but they
  106.     // allow you to set several options which control the behavior of the framework.
  107.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  108.     DXUTCreateWindow( L"Enhanced Mesh - N-Patches" );
  109.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  110.  
  111.     // Pass control to the sample framework for handling the message pump and 
  112.     // dispatching render calls. The sample framework will call your FrameMove 
  113.     // and FrameRender callback when there is idle time between handling window messages.
  114.     DXUTMainLoop();
  115.                                                                             
  116.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  117.     // appropriate callback functions and therefore don't require any cleanup code here.
  118.  
  119.     return DXUTGetExitCode();
  120. }
  121.  
  122.  
  123. //--------------------------------------------------------------------------------------
  124. // Initialize the app 
  125. //--------------------------------------------------------------------------------------
  126. void InitApp()
  127. {
  128.     // Initialize dialogs
  129.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  130.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  131.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  132.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  133.  
  134.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 10; 
  135.     g_SampleUI.AddComboBox( IDC_FILLMODE, 10, iY, 150, 24, L'F' );
  136.     g_SampleUI.GetComboBox( IDC_FILLMODE )->AddItem( L"(F)illmode: Solid", (void*)0 );
  137.     g_SampleUI.GetComboBox( IDC_FILLMODE )->AddItem( L"(F)illmode: Wireframe", (void*)1 );
  138.     g_SampleUI.AddStatic( IDC_SEGMENTLABEL, L"Number of segments: 2", 10, iY += 30, 150, 16 );
  139.     g_SampleUI.AddSlider( IDC_SEGMENT, 10, iY += 14, 150, 24, 1, 10, 2 );
  140.     g_SampleUI.AddCheckBox( IDC_HWNPATCHES, L"Use hardware N-patches", 10, iY += 26, 150, 20, true, L'H' );
  141. }
  142.  
  143.  
  144. //--------------------------------------------------------------------------------------
  145. // Called during device initialization, this code checks the device for some 
  146. // minimum set of capabilities, and rejects those that don't pass by returning false.
  147. //--------------------------------------------------------------------------------------
  148. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  149.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  150. {
  151.     // Skip backbuffer formats that don't support alpha blending
  152.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  153.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  154.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  155.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  156.         return false;
  157.  
  158.     // Must support pixel shader 1.1
  159.     if( pCaps->PixelShaderVersion < D3DPS_VERSION( 1, 1 ) )
  160.         return false;
  161.  
  162.     return true;
  163. }
  164.  
  165.  
  166. //--------------------------------------------------------------------------------------
  167. // This callback function is called immediately before a device is created to allow the 
  168. // application to modify the device settings. The supplied pDeviceSettings parameter 
  169. // contains the settings that the framework has selected for the new device, and the 
  170. // application can make any desired changes directly to this structure.  Note however that 
  171. // the sample framework will not correct invalid device settings so care must be taken 
  172. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  173. //--------------------------------------------------------------------------------------
  174. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  175. {
  176.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  177.     // then switch to SWVP.
  178.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  179.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  180.     {
  181.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  182.     }
  183.     else
  184.     {
  185.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  186.     }
  187.  
  188.     // This application is designed to work on a pure device by not using 
  189.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  190.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  191.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  192.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  193.  
  194.     // Debugging vertex shaders requires either REF or software vertex processing 
  195.     // and debugging pixel shaders requires REF.  
  196. #ifdef DEBUG_VS
  197.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  198.     {
  199.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  200.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  201.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  202.     }
  203. #endif
  204. #ifdef DEBUG_PS
  205.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  206. #endif
  207. }
  208.  
  209.  
  210. //--------------------------------------------------------------------------------------
  211. // Generate a mesh that can be tesselated.
  212. HRESULT GenerateEnhancedMesh( IDirect3DDevice9 *pd3dDevice, UINT dwNewNumSegs )
  213. {
  214.     LPD3DXMESH pMeshEnhancedSysMem = NULL;
  215.     LPD3DXMESH pMeshTemp;
  216.     HRESULT    hr;
  217.  
  218.     if( g_pMeshSysMem == NULL )
  219.         return S_OK;
  220.  
  221.     // if using hw, just copy the mesh
  222.     if( g_bUseHWNPatches )
  223.     {
  224.         hr = g_pMeshSysMem->CloneMeshFVF( D3DXMESH_WRITEONLY | D3DXMESH_NPATCHES | 
  225.             (g_pMeshSysMem->GetOptions() & D3DXMESH_32BIT), 
  226.             g_pMeshSysMem->GetFVF(), pd3dDevice, &pMeshTemp );
  227.         if( FAILED(hr) )
  228.             return hr;
  229.     }
  230.     else  // tesselate the mesh in sw
  231.     {
  232.         // Create an enhanced version of the mesh, will be in sysmem since source is
  233.         hr = D3DXTessellateNPatches( g_pMeshSysMem, (DWORD*)g_pbufAdjacency->GetBufferPointer(), 
  234.                                      (float)dwNewNumSegs, FALSE, &pMeshEnhancedSysMem, NULL );
  235.         if( FAILED(hr) )
  236.         {
  237.             // If the tessellate failed, there might have been more triangles or vertices 
  238.             // than can fit into a 16bit mesh, so try cloning to 32bit before tessellation
  239.  
  240.             hr = g_pMeshSysMem->CloneMeshFVF( D3DXMESH_SYSTEMMEM | D3DXMESH_32BIT, 
  241.                 g_pMeshSysMem->GetFVF(), pd3dDevice, &pMeshTemp );
  242.             if (FAILED(hr))
  243.                 return hr;
  244.  
  245.             hr = D3DXTessellateNPatches( pMeshTemp, (DWORD*)g_pbufAdjacency->GetBufferPointer(), 
  246.                                          (float)dwNewNumSegs, FALSE, &pMeshEnhancedSysMem, NULL );
  247.             if( FAILED(hr) )
  248.             {
  249.                 pMeshTemp->Release();
  250.                 return hr;
  251.             }
  252.  
  253.             pMeshTemp->Release();
  254.         }
  255.  
  256.         // Make a vid mem version of the mesh  
  257.         // Only set WRITEONLY if it doesn't use 32bit indices, because those 
  258.         // often need to be emulated, which means that D3DX needs read-access.
  259.         DWORD dwMeshEnhancedFlags = pMeshEnhancedSysMem->GetOptions() & D3DXMESH_32BIT;
  260.         if( (dwMeshEnhancedFlags & D3DXMESH_32BIT) == 0)
  261.             dwMeshEnhancedFlags |= D3DXMESH_WRITEONLY;
  262.         hr = pMeshEnhancedSysMem->CloneMeshFVF( dwMeshEnhancedFlags, g_pMeshSysMem->GetFVF(),
  263.                                                 pd3dDevice, &pMeshTemp );
  264.         if( FAILED(hr) )
  265.         {
  266.             SAFE_RELEASE( pMeshEnhancedSysMem );
  267.             return hr;
  268.         }
  269.  
  270.         // Latch in the enhanced mesh
  271.         SAFE_RELEASE( pMeshEnhancedSysMem );
  272.     }
  273.  
  274.     SAFE_RELEASE( g_pMeshEnhanced );
  275.     g_pMeshEnhanced = pMeshTemp;
  276.     g_dwNumSegs     = dwNewNumSegs;
  277.  
  278.     return S_OK;
  279. }
  280.  
  281.  
  282. //--------------------------------------------------------------------------------------
  283. // This callback function will be called immediately after the Direct3D device has been 
  284. // created, which will happen during application initialization and windowed/full screen 
  285. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  286. // resources need to be reloaded whenever the device is destroyed. Resources created  
  287. // here should be released in the OnDestroyDevice callback. 
  288. //--------------------------------------------------------------------------------------
  289. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  290. {
  291.     WCHAR wszMeshDir[MAX_PATH];
  292.     WCHAR wszWorkingDir[MAX_PATH];
  293.     IDirect3DVertexBuffer9* pVB = NULL;
  294.     HRESULT hr;
  295.  
  296.     D3DCAPS9 d3dCaps;
  297.     pd3dDevice->GetDeviceCaps( &d3dCaps );
  298.     if( !( d3dCaps.DevCaps & D3DDEVCAPS_NPATCHES ) )
  299.     {
  300.         // No hardware support. Disable the checkbox.
  301.         g_bUseHWNPatches = false;
  302.         g_SampleUI.GetCheckBox( IDC_HWNPATCHES )->SetChecked( false );
  303.         g_SampleUI.GetCheckBox( IDC_HWNPATCHES )->SetEnabled( false );
  304.     } else
  305.         g_SampleUI.GetCheckBox( IDC_HWNPATCHES )->SetEnabled( true );
  306.  
  307.     // Initialize the font
  308.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
  309.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
  310.                          L"Arial", &g_pFont ) );
  311.  
  312.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  313.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  314.     // processing, and debugging pixel shaders requires REF.  The 
  315.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  316.     // shader debugger.  It enables source level debugging, prevents instruction 
  317.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  318.     // against the next higher available software target, which ensures that the 
  319.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  320.     // flags will cause slower rendering since the shaders will be unoptimized and 
  321.     // forced into software.  See the DirectX documentation for more information about 
  322.     // using the shader debugger.
  323.     DWORD dwShaderFlags = 0;
  324.     #ifdef DEBUG_VS
  325.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  326.     #endif
  327.     #ifdef DEBUG_PS
  328.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  329.     #endif
  330.  
  331.     // Read the D3DX effect file
  332.     WCHAR str[MAX_PATH];
  333.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"EnhancedMesh.fx" ) );
  334.  
  335.     // If this fails, there should be debug output as to
  336.     // they the .fx file failed to compile
  337.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  338.                                         NULL, &g_pEffect, NULL ) );
  339.  
  340.     // Load the mesh
  341.     V_RETURN( DXUTFindDXSDKMediaFileCch( wszMeshDir, MAX_PATH, MESHFILENAME ) );
  342.     V_RETURN( D3DXLoadMeshFromX( wszMeshDir, D3DXMESH_SYSTEMMEM, pd3dDevice,
  343.                                  &g_pbufAdjacency, &g_pbufMaterials, NULL, &g_dwNumMaterials,
  344.                                  &g_pMeshSysMem ) );
  345.  
  346.     // Initialize the mesh directory string
  347.     WCHAR *pwszLastBSlash = wcsrchr( wszMeshDir, L'\\' );
  348.     if( pwszLastBSlash )
  349.         *pwszLastBSlash = L'\0';
  350.     else
  351.         lstrcpyW( wszMeshDir, L"." );
  352.  
  353.     // Lock the vertex buffer, to generate a simple bounding sphere
  354.     hr = g_pMeshSysMem->GetVertexBuffer( &pVB );
  355.     if( FAILED(hr) )
  356.         return hr;
  357.  
  358.     void* pVertices = NULL;
  359.     hr = pVB->Lock( 0, 0, &pVertices, 0 );
  360.     if( FAILED(hr) )
  361.     {
  362.         SAFE_RELEASE( pVB );
  363.         return hr;
  364.     }
  365.  
  366.     hr = D3DXComputeBoundingSphere( (D3DXVECTOR3*)pVertices, g_pMeshSysMem->GetNumVertices(),
  367.                                     D3DXGetFVFVertexSize(g_pMeshSysMem->GetFVF()), &g_vObjectCenter,
  368.                                     &g_fObjectRadius );
  369.     pVB->Unlock();
  370.     SAFE_RELEASE( pVB );
  371.  
  372.     if( FAILED(hr) )
  373.         return hr;
  374.  
  375.     if( 0 == g_dwNumMaterials )
  376.         return E_INVALIDARG;
  377.  
  378.     D3DXMatrixTranslation( &g_mCenterWorld, -g_vObjectCenter.x, -g_vObjectCenter.y, -g_vObjectCenter.z );
  379.  
  380.     // Change the current directory to the .x's directory so
  381.     // that the search can find the texture files.
  382.     GetCurrentDirectory( MAX_PATH, wszWorkingDir );
  383.     wszWorkingDir[MAX_PATH - 1] = L'\0';
  384.     SetCurrentDirectory( wszMeshDir );
  385.  
  386.     // Get the array of materials out of the returned buffer, allocate a
  387.     // texture array, and load the textures
  388.     g_pMaterials = (D3DXMATERIAL*)g_pbufMaterials->GetBufferPointer();
  389.     g_ppTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials];
  390.  
  391.     for( UINT i = 0; i < g_dwNumMaterials; i++ )
  392.     {
  393.         WCHAR strTexturePath[512] = L"";
  394.         WCHAR *wszName;
  395.         WCHAR wszBuf[MAX_PATH];
  396.         wszName = wszBuf;
  397.         MultiByteToWideChar( CP_ACP, 0, g_pMaterials[i].pTextureFilename, -1, wszBuf, MAX_PATH );
  398.         wszBuf[MAX_PATH - 1] = L'\0';
  399.         DXUTFindDXSDKMediaFileCch( strTexturePath, 512, wszName );
  400.         if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, strTexturePath,
  401.                                                &g_ppTextures[i] ) ) )
  402.             g_ppTextures[i] = NULL;
  403.     }
  404.     SetCurrentDirectory( wszWorkingDir );
  405.  
  406.     // Make sure there are normals, which are required for the tesselation
  407.     // enhancement.
  408.     if( !( g_pMeshSysMem->GetFVF() & D3DFVF_NORMAL ) )
  409.     {
  410.         ID3DXMesh* pTempMesh;
  411.  
  412.         V_RETURN( g_pMeshSysMem->CloneMeshFVF( g_pMeshSysMem->GetOptions(),
  413.                                                g_pMeshSysMem->GetFVF() | D3DFVF_NORMAL,
  414.                                                pd3dDevice, &pTempMesh ) );
  415.  
  416.         D3DXComputeNormals( pTempMesh, NULL );
  417.  
  418.         SAFE_RELEASE( g_pMeshSysMem );
  419.         g_pMeshSysMem = pTempMesh;
  420.     }
  421.  
  422.     // Create the 1x1 white default texture
  423.     V_RETURN( pd3dDevice->CreateTexture( 1, 1, 1, 0, D3DFMT_A8R8G8B8,
  424.                                          D3DPOOL_MANAGED, &g_pDefaultTex, NULL ) );
  425.     D3DLOCKED_RECT lr;
  426.     V_RETURN( g_pDefaultTex->LockRect( 0, &lr, NULL, 0 ) );
  427.     *(LPDWORD)lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 );
  428.     V_RETURN( g_pDefaultTex->UnlockRect( 0 ) );
  429.  
  430.     // Setup the camera's view parameters
  431.     D3DXVECTOR3 vecEye(0.0f, 0.0f, -5.0f);
  432.     D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
  433.     g_Camera.SetViewParams( &vecEye, &vecAt );
  434.  
  435.     return S_OK;
  436. }
  437.  
  438.  
  439. //--------------------------------------------------------------------------------------
  440. // This callback function will be called immediately after the Direct3D device has been 
  441. // reset, which will happen after a lost device scenario. This is the best location to 
  442. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  443. // the device is lost. Resources created here should be released in the OnLostDevice 
  444. // callback. 
  445. //--------------------------------------------------------------------------------------
  446. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  447.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  448. {
  449.     HRESULT hr;
  450.  
  451.     if( g_pFont )
  452.         V_RETURN( g_pFont->OnResetDevice() );
  453.     if( g_pEffect )
  454.         V_RETURN( g_pEffect->OnResetDevice() );
  455.  
  456.     // Create a sprite to help batch calls when drawing many lines of text
  457.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  458.  
  459.     V_RETURN( GenerateEnhancedMesh( pd3dDevice, g_dwNumSegs ) );
  460.  
  461.     if( g_bWireframe )
  462.         pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
  463.     else
  464.         pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
  465.  
  466.     // Setup the camera's projection parameters
  467.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  468.     g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 1000.0f );
  469.     g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  470.  
  471.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  472.     g_HUD.SetSize( 170, 170 );
  473.     g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, pBackBufferSurfaceDesc->Height-350 );
  474.     g_SampleUI.SetSize( 170, 300 );
  475.  
  476.     return S_OK;
  477. }
  478.  
  479.  
  480. //--------------------------------------------------------------------------------------
  481. // This callback function will be called once at the beginning of every frame. This is the
  482. // best location for your application to handle updates to the scene, but is not 
  483. // intended to contain actual rendering calls, which should instead be placed in the 
  484. // OnFrameRender callback.  
  485. //--------------------------------------------------------------------------------------
  486. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  487. {
  488.     // Update the camera's position based on user input 
  489.     g_Camera.FrameMove( fElapsedTime );
  490.  
  491.     pd3dDevice->SetTransform( D3DTS_WORLD, g_Camera.GetWorldMatrix() );
  492.     pd3dDevice->SetTransform( D3DTS_VIEW, g_Camera.GetViewMatrix() );
  493. }
  494.  
  495.  
  496. //--------------------------------------------------------------------------------------
  497. // This callback function will be called at the end of every frame to perform all the 
  498. // rendering calls for the scene, and it will also be called if the window needs to be 
  499. // repainted. After this function has returned, the sample framework will call 
  500. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  501. //--------------------------------------------------------------------------------------
  502. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  503. {
  504.     HRESULT hr;
  505.     D3DXMATRIXA16 mWorld;
  506.     D3DXMATRIXA16 mView;
  507.     D3DXMATRIXA16 mProj;
  508.     D3DXMATRIXA16 mWorldViewProjection;
  509.     
  510.     // Clear the render target and the zbuffer 
  511.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 66, 75, 121), 1.0f, 0) );
  512.  
  513.     // Render the scene
  514.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  515.     {
  516.         // Get the projection & view matrix from the camera class
  517.         mWorld = *g_Camera.GetWorldMatrix();
  518.         mProj = *g_Camera.GetProjMatrix();
  519.         mView = *g_Camera.GetViewMatrix();
  520.  
  521.         mWorldViewProjection = g_mCenterWorld * mWorld * mView * mProj;
  522.  
  523.         // Update the effect's variables.  Instead of using strings, it would 
  524.         // be more efficient to cache a handle to the parameter by calling 
  525.         // ID3DXEffect::GetParameterByName
  526.         V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  527.         V( g_pEffect->SetMatrix( "g_mWorld", &mWorld ) );
  528.         V( g_pEffect->SetFloat( "g_fTime", (float)fTime ) );
  529.  
  530.         if( g_bUseHWNPatches )
  531.         {
  532.             float fNumSegs;
  533.  
  534.             fNumSegs = (float)g_dwNumSegs;
  535.             pd3dDevice->SetNPatchMode( fNumSegs );
  536.         }
  537.  
  538.         UINT cPasses;
  539.         V( g_pEffect->Begin( &cPasses, 0 ) );
  540.         for( UINT p = 0; p < cPasses; ++p )
  541.         {
  542.             V( g_pEffect->BeginPass( p ) );
  543.  
  544.             // set and draw each of the materials in the mesh
  545.             for( UINT i = 0; i < g_dwNumMaterials; i++ )
  546.             {
  547.                 V( g_pEffect->SetVector( "g_vDiffuse", (D3DXVECTOR4*)&g_pMaterials[i].MatD3D.Diffuse ) );
  548.                 if( g_ppTextures[i] )
  549.                 {
  550.                     V( g_pEffect->SetTexture( "g_txScene", g_ppTextures[i] ) );
  551.                 }
  552.                 else
  553.                 {
  554.                     V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
  555.                 }
  556.                 V( g_pEffect->CommitChanges() );
  557.  
  558.                 g_pMeshEnhanced->DrawSubset( i );
  559.             }
  560.  
  561.             V( g_pEffect->EndPass() );
  562.         }
  563.         V( g_pEffect->End() );
  564.  
  565.         if( g_bUseHWNPatches )
  566.         {
  567.             pd3dDevice->SetNPatchMode( 0 );
  568.         }
  569.  
  570.         RenderText();
  571.         V( g_HUD.OnRender( fElapsedTime ) );
  572.         V( g_SampleUI.OnRender( fElapsedTime ) );
  573.  
  574.         V( pd3dDevice->EndScene() );
  575.     }
  576. }
  577.  
  578.  
  579. //--------------------------------------------------------------------------------------
  580. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  581. // efficient text rendering.
  582. //--------------------------------------------------------------------------------------
  583. void RenderText()
  584. {
  585.     // The helper object simply helps keep track of text position, and color
  586.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  587.     // If NULL is passed in as the sprite object, then it will work however the 
  588.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  589.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  590.  
  591.     // Output statistics
  592.     txtHelper.Begin();
  593.     txtHelper.SetInsertionPos( 5, 5 );
  594.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  595.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  596.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  597.     
  598.     // Draw help
  599.     if( g_bShowHelp )
  600.     {
  601.         const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  602.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*6 );
  603.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  604.         txtHelper.DrawTextLine( L"Controls (F1 to hide):" );
  605.  
  606.         txtHelper.SetInsertionPos( 40, pd3dsdBackBuffer->Height-15*5 );
  607.         txtHelper.DrawTextLine( L"Rotate mesh: Left click drag\n"
  608.                                 L"Rotate camera: right click drag\n"
  609.                                 L"Zoom: Mouse wheel\n"
  610.                                 L"Quit: ESC" );
  611.     }
  612.     else
  613.     {
  614.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  615.         txtHelper.DrawTextLine( L"Press F1 for help" );
  616.     }
  617.  
  618.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  619.     txtHelper.SetInsertionPos( 10, 65 );
  620.     txtHelper.DrawFormattedTextLine( L"NumSegs: %d\n", g_dwNumSegs );
  621.     txtHelper.DrawFormattedTextLine( L"NumFaces: %d\n", ( g_pMeshEnhanced == NULL) ? 0 : g_pMeshEnhanced->GetNumFaces() );
  622.     txtHelper.DrawFormattedTextLine( L"NumVertices: %d\n", ( g_pMeshEnhanced == NULL) ? 0 : g_pMeshEnhanced->GetNumVertices() );
  623.  
  624.     txtHelper.End();
  625. }
  626.  
  627.  
  628. //--------------------------------------------------------------------------------------
  629. // Before handling window messages, the sample framework passes incoming windows 
  630. // messages to the application through this callback function. If the application sets 
  631. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  632. //--------------------------------------------------------------------------------------
  633. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  634. {
  635.     // Give the dialogs a chance to handle the message first
  636.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  637.     if( *pbNoFurtherProcessing )
  638.         return 0;
  639.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  640.     if( *pbNoFurtherProcessing )
  641.         return 0;
  642.  
  643.     // Pass all remaining windows messages to camera so it can respond to user input
  644.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  645.  
  646.     return 0;
  647. }
  648.  
  649.  
  650. //--------------------------------------------------------------------------------------
  651. // As a convenience, the sample framework inspects the incoming windows messages for
  652. // keystroke messages and decodes the message parameters to pass relevant keyboard
  653. // messages to the application.  The framework does not remove the underlying keystroke 
  654. // messages, which are still passed to the application's MsgProc callback.
  655. //--------------------------------------------------------------------------------------
  656. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  657. {
  658.     if( bKeyDown )
  659.     {
  660.         switch( nChar )
  661.         {
  662.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  663.         }
  664.     }
  665. }
  666.  
  667.  
  668. //--------------------------------------------------------------------------------------
  669. // Handles the GUI events
  670. //--------------------------------------------------------------------------------------
  671. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  672. {
  673.     switch( nControlID )
  674.     {
  675.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  676.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  677.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  678.         case IDC_FILLMODE:
  679.         {
  680.             g_bWireframe = ((CDXUTComboBox*)pControl)->GetSelectedData() != 0;
  681.             IDirect3DDevice9 *pd3dDevice = DXUTGetD3DDevice();
  682.             pd3dDevice->SetRenderState( D3DRS_FILLMODE, g_bWireframe ? D3DFILL_WIREFRAME : D3DFILL_SOLID );
  683.             break;
  684.         }
  685.         case IDC_SEGMENT:
  686.             g_dwNumSegs = ((CDXUTSlider*)pControl)->GetValue();
  687.             WCHAR wszBuf[256];
  688.             swprintf( wszBuf, L"Number of segments: %u", g_dwNumSegs );
  689.             g_SampleUI.GetStatic( IDC_SEGMENTLABEL )->SetText( wszBuf );
  690.             GenerateEnhancedMesh( DXUTGetD3DDevice(), g_dwNumSegs );
  691.             break;
  692.         case IDC_HWNPATCHES:
  693.             g_bUseHWNPatches = ((CDXUTCheckBox*)pControl)->GetChecked();
  694.             GenerateEnhancedMesh( DXUTGetD3DDevice(), g_dwNumSegs );
  695.             break;
  696.     }
  697. }
  698.  
  699.  
  700. //--------------------------------------------------------------------------------------
  701. // This callback function will be called immediately after the Direct3D device has 
  702. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  703. // in the OnResetDevice callback should be released here, which generally includes all 
  704. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  705. // information about lost devices.
  706. //--------------------------------------------------------------------------------------
  707. void CALLBACK OnLostDevice()
  708. {
  709.     if( g_pFont )
  710.         g_pFont->OnLostDevice();
  711.     if( g_pEffect )
  712.         g_pEffect->OnLostDevice();
  713.     SAFE_RELEASE( g_pTextSprite );
  714.     SAFE_RELEASE( g_pMeshEnhanced );
  715. }
  716.  
  717.  
  718. //--------------------------------------------------------------------------------------
  719. // This callback function will be called immediately after the Direct3D device has 
  720. // been destroyed, which generally happens as a result of application termination or 
  721. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  722. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  723. //--------------------------------------------------------------------------------------
  724. void CALLBACK OnDestroyDevice()
  725. {
  726.     SAFE_RELEASE(g_pEffect);
  727.     SAFE_RELEASE(g_pFont);
  728.  
  729.     for( UINT i = 0; i < g_dwNumMaterials; i++ )
  730.         SAFE_RELEASE( g_ppTextures[i] );
  731.  
  732.     SAFE_RELEASE( g_pDefaultTex );
  733.     SAFE_DELETE_ARRAY( g_ppTextures );
  734.     SAFE_RELEASE( g_pMeshSysMem );
  735.     SAFE_RELEASE( g_pbufMaterials );
  736.     SAFE_RELEASE( g_pbufAdjacency );
  737.     g_dwNumMaterials = 0L;
  738. }
  739.  
  740.  
  741.  
  742.